﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using System.Diagnostics;
using SimpleIR;

namespace InterpreterCore
{
	/// <summary>
	/// Representation of a numeric value (signed, unsigned, or float)
	/// </summary>
	[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Explicit)]
	internal struct StackNumericValue
	{
		[System.Runtime.InteropServices.FieldOffset(0)]
		private readonly int m_i32value;

		[System.Runtime.InteropServices.FieldOffset(0)]
		private readonly long m_i64value;

		[System.Runtime.InteropServices.FieldOffset(0)]
		private readonly uint m_u32value;

		[System.Runtime.InteropServices.FieldOffset(0)]
		private readonly ulong m_u64value;

		[System.Runtime.InteropServices.FieldOffset(0)]
		private readonly double m_floatvalue;

		private StackNumericValue(int iv)
		{
			this.m_i32value = 0;
			this.m_i64value = 0;
			this.m_u32value = 0;
			this.m_u64value = 0;
			this.m_floatvalue = 0.0;

			this.m_i32value = iv;
		}

		private StackNumericValue(long lv)
		{
			this.m_i32value = 0;
			this.m_i64value = 0;
			this.m_u32value = 0;
			this.m_u64value = 0;
			this.m_floatvalue = 0.0;

			this.m_i64value = lv;
		}

		private StackNumericValue(uint uiv)
		{
			this.m_i32value = 0;
			this.m_i64value = 0;
			this.m_u32value = 0;
			this.m_u64value = 0;
			this.m_floatvalue = 0.0;

			this.m_u32value = uiv;
		}

		private StackNumericValue(ulong ulv)
		{
			this.m_i32value = 0;
			this.m_i64value = 0;
			this.m_u32value = 0;
			this.m_u64value = 0;
			this.m_floatvalue = 0.0;

			this.m_u64value = ulv;
		}

		private StackNumericValue(double dv)
		{
			this.m_i32value = 0;
			this.m_i64value = 0;
			this.m_u32value = 0;
			this.m_u64value = 0;
			this.m_floatvalue = 0.0;

			this.m_floatvalue = dv;
		}

		public string ToString(IRType oftype)
		{
			if(oftype is IREvalStackTypeInt32)
				return String.Format("{0}i ({1}u)", this.m_i32value, this.m_u32value);
			else if(oftype is IREvalStackTypeInt64)
				return String.Format("{0}l ({1}ul)", this.m_i64value, this.m_u64value);
			else
				return String.Format("{0}f", this.m_floatvalue);
		}

		/// <summary>
		/// The value formatted as a string for display in the debugger.
		/// </summary>
		internal string DebuggerString(IRType oftype)
		{
			if(oftype is IREvalStackTypeInt32)
				return String.Format("{0}i", this.m_i32value);
			else if(oftype is IREvalStackTypeInt64)
				return String.Format("{0}l", this.m_i64value);
			else
				return String.Format("{0}f", this.m_floatvalue);
		}

		/// <summary>
		/// The value formatted as a string in a format for emitting in the trace.
		/// </summary>
		internal string EmitForTrace(IRType oftype)
		{
			if(oftype is IREvalStackTypeInt32)
				return this.m_u32value.ToString();
			else if(oftype is IREvalStackTypeInt64)
				return this.m_u64value.ToString();
			else
				return this.m_floatvalue.ToString();
		}

		/// <summary>
		/// The value formatted and output for a heap dump.
		/// </summary>
		internal void SerializeForHeapDump(System.IO.TextWriter dumpstr, IRType oftype)
		{
			if(oftype is IREvalStackTypeInt32)
				dumpstr.Write(this.m_u32value);
			else if(oftype is IREvalStackTypeInt64)
				dumpstr.Write(this.m_u64value);
			else
				dumpstr.Write(this.m_floatvalue);
		}

		/// <summary>
		/// Parse a numeric value of the given type from a string.
		/// </summary>
		internal static StackNumericValue ParseValue(IREvalStackPrimitiveType svt, string val)
		{
			if(svt is IREvalStackTypeInt32)
			{
				uint uv = UInt32.Parse(val);
				return new StackNumericValue(uv);
			}
			else if(svt is IREvalStackTypeInt64)
			{
				ulong ulv = UInt64.Parse(val);
				return new StackNumericValue(ulv);
			}
			else
			{
				double dv = Double.Parse(val);
				return new StackNumericValue(dv);
			}
		}

		///////////////////////////////////////////////////////////////////////////////
		//Big block of constructors and accessors

		internal static StackNumericValue MakeZeroStackValue()
		{ return new StackNumericValue(0UL); }

		internal static StackNumericValue MakeFromNumericValue(NumericValue nv)
		{
			if(nv.ValType is IRSignedIntegerType)
			{
				if(((IRSignedIntegerType)nv.ValType).SignedTag == IRSignedIntegerType.SignedTypeTag.Int64Tag)
					return new StackNumericValue((long)nv.ReadSignedValue());
				else
					return new StackNumericValue((int)nv.ReadSignedValue());
			}
			else if(nv.ValType is IRUnSignedIntegerType)
			{
				if(((IRUnSignedIntegerType)nv.ValType).UnSignedTag == IRUnSignedIntegerType.UnsignedTypeTag.UInt64Tag)
					return new StackNumericValue((ulong)nv.ReadUnSignedValue());
				else
					return new StackNumericValue((uint)nv.ReadUnSignedValue());
			}
			else
			{
				return new StackNumericValue((double)nv.ReadFloatValue());
			}
		}

		internal NumericValue ConvertToNumericValue_Signed(IRPrimitiveNumericType oftype, IREvalStackPrimitiveType currenttype)
		{
			if(currenttype is IREvalStackTypeInt32)
			{
				if(oftype is IRSignedIntegerType)
				{
					long sval;
					IRSignedIntegerType softype = (IRSignedIntegerType)oftype;

					switch(softype.SignedTag)
					{
						case IRSignedIntegerType.SignedTypeTag.BoolTag:
							sval = this.m_i32value & 0x1;
							break;
						case IRSignedIntegerType.SignedTypeTag.SByteTag:
							sval = (sbyte)(this.m_i32value & 0xFF);
							break;
						case IRSignedIntegerType.SignedTypeTag.Int16Tag:
							sval = (short)(this.m_i32value & 0xFFFF);
							break;
						case IRSignedIntegerType.SignedTypeTag.Int32Tag:
							sval = this.m_i32value;
							break;
						default:
							sval = this.m_i32value;
							break;
					}

					return NumericValue.MakeSignedValueOfType(sval, softype);
				}
				else
				{
					IRFloatingPointType foftype = (IRFloatingPointType)oftype;

					return NumericValue.MakeFloatValueOfType((double)this.m_i32value, foftype);
				}
			}
			else if(currenttype is IREvalStackTypeInt64)
			{
				if(oftype is IRSignedIntegerType)
				{
					long sval;
					IRSignedIntegerType softype = (IRSignedIntegerType)oftype;

					switch(softype.SignedTag)
					{
						case IRSignedIntegerType.SignedTypeTag.BoolTag:
							sval = this.m_i64value & 0x1;
							break;
						case IRSignedIntegerType.SignedTypeTag.SByteTag:
							sval = (sbyte)(this.m_i64value & 0xFF);
							break;
						case IRSignedIntegerType.SignedTypeTag.Int16Tag:
							sval = (short)(this.m_i64value & 0xFFFF);
							break;
						case IRSignedIntegerType.SignedTypeTag.Int32Tag:
							sval = (int)(this.m_i64value & 0xFFFFFFFF);
							break;
						default:
							sval = this.m_i64value;
							break;
					}

					return NumericValue.MakeSignedValueOfType(sval, softype);
				}
				else
				{
					IRFloatingPointType foftype = (IRFloatingPointType)oftype;

					return NumericValue.MakeFloatValueOfType((double)this.m_i64value, foftype);
				}
			}
			else
			{
				IRFloatingPointType foftype = (IRFloatingPointType)oftype;

				return NumericValue.MakeFloatValueOfType((double)this.m_floatvalue, foftype);
			}
		}

		internal NumericValue ConvertToNumericValue_UnSigned(IRPrimitiveNumericType oftype, IREvalStackPrimitiveType currenttype)
		{
			if(currenttype is IREvalStackTypeInt32)
			{
				if(oftype is IRUnSignedIntegerType)
				{
					ulong uval;
					IRUnSignedIntegerType uoftype = (IRUnSignedIntegerType)oftype;

					switch(uoftype.UnSignedTag)
					{
						case IRUnSignedIntegerType.UnsignedTypeTag.ByteTag:
							uval = (byte)(this.m_u32value & 0xFF);
							break;
						case IRUnSignedIntegerType.UnsignedTypeTag.CharTag:
							uval = (char)(this.m_u32value & 0xFFFF);
							break;
						case IRUnSignedIntegerType.UnsignedTypeTag.UInt16Tag:
							uval = (ushort)(this.m_u32value & 0xFFFF);
							break;
						case IRUnSignedIntegerType.UnsignedTypeTag.UInt32Tag:
							uval = this.m_u32value;
							break;
						default:
							uval = this.m_u32value;
							break;
					}

					return NumericValue.MakeUnSignedValueOfType(uval, uoftype);
				}
				else
				{
					IRFloatingPointType foftype = (IRFloatingPointType)oftype;

					return NumericValue.MakeFloatValueOfType((double)this.m_u32value, foftype);
				}
			}
			else if(currenttype is IREvalStackTypeInt64)
			{
				if(oftype is IRUnSignedIntegerType)
				{
					ulong uval;
					IRUnSignedIntegerType uoftype = (IRUnSignedIntegerType)oftype;

					switch(uoftype.UnSignedTag)
					{
						case IRUnSignedIntegerType.UnsignedTypeTag.ByteTag:
							uval = (byte)(this.m_u64value & 0xFF);
							break;
						case IRUnSignedIntegerType.UnsignedTypeTag.CharTag:
							uval = (char)(this.m_u64value & 0xFFFF);
							break;
						case IRUnSignedIntegerType.UnsignedTypeTag.UInt16Tag:
							uval = (ushort)(this.m_u64value & 0xFFFF);
							break;
						case IRUnSignedIntegerType.UnsignedTypeTag.UInt32Tag:
							uval = (uint)(this.m_u64value & 0xFFFFFFFF);
							break;
						default:
							uval = this.m_u64value;
							break;
					}

					return NumericValue.MakeUnSignedValueOfType(uval, uoftype);
				}
				else
				{
					IRFloatingPointType foftype = (IRFloatingPointType)oftype;

					return NumericValue.MakeFloatValueOfType((double)this.m_u64value, foftype);
				}
			}
			else
			{
				IRFloatingPointType foftype = (IRFloatingPointType)oftype;

				return NumericValue.MakeFloatValueOfType((double)this.m_floatvalue, foftype);
			}
		}

		internal NumericValue ConvertToNumericValue_Basic(IRType oftype, IREvalStackPrimitiveType currenttype)
		{
			if(oftype is IREnumType)
				oftype = ((IREnumType)oftype).UnerlyingNumericType;

			if(oftype is IRSignedIntegerType)
				return this.ConvertToNumericValue_Signed((IRPrimitiveNumericType)oftype, currenttype);
			else if(oftype is IRUnSignedIntegerType)
				return this.ConvertToNumericValue_UnSigned((IRPrimitiveNumericType)oftype, currenttype);
			else
				return NumericValue.MakeFloatValueOfType(this.m_floatvalue, (IRFloatingPointType)oftype);
		}

		///////////////////////////////////////////////////////////////////////////////
		//Big block of ops

		//////////////
		//Primitive Compare

		/// <summary>
		/// Simulate the equality operation.
		/// </summary>
		internal static StackNumericValue SimulatePrimEQ(StackNumericValue sn1, StackNumericValue sn2, IREvalStackPrimitiveType evst)
		{
			if(evst is IREvalStackTypeInt32)
				return new StackNumericValue((int)(sn1.m_u32value == sn2.m_u32value ? 1 : 0));
			else if(evst is IREvalStackTypeInt64)
				return new StackNumericValue((int)(sn1.m_u64value == sn2.m_u64value ? 1 : 0));
			else
				return new StackNumericValue((int)(sn1.m_floatvalue == sn2.m_floatvalue ? 1 : 0));
		}

		/// <summary>
		/// Simulate the less operation.
		/// </summary>
		internal static StackNumericValue SimulateLess(StackNumericValue sn1, StackNumericValue sn2, IREvalStackPrimitiveType evst)
		{
			if(evst is IREvalStackTypeInt32)
				return new StackNumericValue((int)(sn1.m_i32value < sn2.m_i32value ? 1 : 0));
			else if(evst is IREvalStackTypeInt64)
				return new StackNumericValue((int)(sn1.m_i64value < sn2.m_i64value ? 1 : 0));
			else
				return new StackNumericValue((int)(sn1.m_floatvalue < sn2.m_floatvalue ? 1 : 0));
		}

		/// <summary>
		/// Simulate the less operation (unsigned).
		/// </summary>
		internal static StackNumericValue SimulateLessUnsigned(StackNumericValue sn1, StackNumericValue sn2, IREvalStackPrimitiveType evst)
		{
			if(evst is IREvalStackTypeInt32)
				return new StackNumericValue((int)(sn1.m_u32value < sn2.m_u32value ? 1 : 0));
			else if(evst is IREvalStackTypeInt64)
				return new StackNumericValue((int)(sn1.m_u64value < sn2.m_u64value ? 1 : 0));
			else
				return new StackNumericValue((int)(sn1.m_floatvalue < sn2.m_floatvalue ? 1 : 0));
		}

		/// <summary>
		/// Simulate the less than or equal operation.
		/// </summary>
		internal static StackNumericValue SimulateLessEQ(StackNumericValue sn1, StackNumericValue sn2, IREvalStackPrimitiveType evst)
		{
			if(evst is IREvalStackTypeInt32)
				return new StackNumericValue((int)(sn1.m_i32value <= sn2.m_i32value ? 1 : 0));
			else if(evst is IREvalStackTypeInt64)
				return new StackNumericValue((int)(sn1.m_i64value <= sn2.m_i64value ? 1 : 0));
			else
				return new StackNumericValue((int)(sn1.m_floatvalue <= sn2.m_floatvalue ? 1 : 0));
		}

		/// <summary>
		/// Simulate the less than or equal operation (unsigned).
		/// </summary>
		internal static StackNumericValue SimulateLessEQUnsigned(StackNumericValue sn1, StackNumericValue sn2, IREvalStackPrimitiveType evst)
		{
			if(evst is IREvalStackTypeInt32)
				return new StackNumericValue((int)(sn1.m_u32value <= sn2.m_u32value ? 1 : 0));
			else if(evst is IREvalStackTypeInt64)
				return new StackNumericValue((int)(sn1.m_u64value <= sn2.m_u64value ? 1 : 0));
			else
				return new StackNumericValue((int)(sn1.m_floatvalue <= sn2.m_floatvalue ? 1 : 0));
		}

		/// <summary>
		/// Simulate the greater operation.
		/// </summary>
		internal static StackNumericValue SimulateGreater(StackNumericValue sn1, StackNumericValue sn2, IREvalStackPrimitiveType evst)
		{
			if(evst is IREvalStackTypeInt32)
				return new StackNumericValue((int)(sn1.m_i32value > sn2.m_i32value ? 1 : 0));
			else if(evst is IREvalStackTypeInt64)
				return new StackNumericValue((int)(sn1.m_i64value > sn2.m_i64value ? 1 : 0));
			else
				return new StackNumericValue((int)(sn1.m_floatvalue > sn2.m_floatvalue ? 1 : 0));
		}

		/// <summary>
		/// Simulate the greater operation (unsigned).
		/// </summary>
		internal static StackNumericValue SimulateGreaterUnsigned(StackNumericValue sn1, StackNumericValue sn2, IREvalStackPrimitiveType evst)
		{
			if(evst is IREvalStackTypeInt32)
				return new StackNumericValue((int)(sn1.m_u32value > sn2.m_u32value ? 1 : 0));
			else if(evst is IREvalStackTypeInt64)
				return new StackNumericValue((int)(sn1.m_u64value > sn2.m_u64value ? 1 : 0));
			else
				return new StackNumericValue((int)(sn1.m_floatvalue > sn2.m_floatvalue ? 1 : 0));
		}

		/// <summary>
		/// Simulate the greater than or equal operation.
		/// </summary>
		internal static StackNumericValue SimulateGreaterEQ(StackNumericValue sn1, StackNumericValue sn2, IREvalStackPrimitiveType evst)
		{
			if(evst is IREvalStackTypeInt32)
				return new StackNumericValue((int)(sn1.m_i32value >= sn2.m_i32value ? 1 : 0));
			else if(evst is IREvalStackTypeInt64)
				return new StackNumericValue((int)(sn1.m_i64value >= sn2.m_i64value ? 1 : 0));
			else
				return new StackNumericValue((int)(sn1.m_floatvalue >= sn2.m_floatvalue ? 1 : 0));
		}

		/// <summary>
		/// Simulate the greater than or equal operation (unsigned).
		/// </summary>
		internal static StackNumericValue SimulateGreaterEQUnsigned(StackNumericValue sn1, StackNumericValue sn2, IREvalStackPrimitiveType evst)
		{
			if(evst is IREvalStackTypeInt32)
				return new StackNumericValue((int)(sn1.m_u32value >= sn2.m_u32value ? 1 : 0));
			else if(evst is IREvalStackTypeInt64)
				return new StackNumericValue((int)(sn1.m_u64value >= sn2.m_u64value ? 1 : 0));
			else
				return new StackNumericValue((int)(sn1.m_floatvalue >= sn2.m_floatvalue ? 1 : 0));
		}

		//////////////
		//Primitive Arith Operations

		/// <summary>
		/// Simulate an add operation.
		/// </summary>
		internal static StackNumericValue SimulateAdd(StackNumericValue sn1, StackNumericValue sn2, IREvalStackPrimitiveType evst)
		{
			if(evst is IREvalStackTypeInt32)
				return new StackNumericValue(sn1.m_i32value + sn2.m_i32value);
			else if(evst is IREvalStackTypeInt64)
				return new StackNumericValue(sn1.m_i64value + sn2.m_i64value);
			else
				return new StackNumericValue(sn1.m_floatvalue + sn2.m_floatvalue);
		}

		/// <summary>
		/// Simulate an add operation (unsigned).
		/// </summary>
		internal static StackNumericValue SimulateAddUnsigned(StackNumericValue sn1, StackNumericValue sn2, IREvalStackPrimitiveType evst)
		{
			if(evst is IREvalStackTypeInt32)
				return new StackNumericValue(sn1.m_u32value + sn2.m_u32value);
			else if(evst is IREvalStackTypeInt64)
				return new StackNumericValue(sn1.m_u64value + sn2.m_u64value);
			else
				return new StackNumericValue(sn1.m_floatvalue + sn2.m_floatvalue);
		}

		/// <summary>
		/// Simulate a divide operation.
		/// </summary>
		internal static StackNumericValue SimulateDiv(StackNumericValue sn1, StackNumericValue sn2, IREvalStackPrimitiveType evst)
		{
			if(evst is IREvalStackTypeInt32)
				return new StackNumericValue(sn1.m_i32value / sn2.m_i32value);
			else if(evst is IREvalStackTypeInt64)
				return new StackNumericValue(sn1.m_i64value / sn2.m_i64value);
			else
				return new StackNumericValue(sn1.m_floatvalue / sn2.m_floatvalue);
		}

		/// <summary>
		/// Simulate an divide operation (unsigned).
		/// </summary>
		internal static StackNumericValue SimulateDivUnsigned(StackNumericValue sn1, StackNumericValue sn2, IREvalStackPrimitiveType evst)
		{
			if(evst is IREvalStackTypeInt32)
				return new StackNumericValue(sn1.m_u32value / sn2.m_u32value);
			else if(evst is IREvalStackTypeInt64)
				return new StackNumericValue(sn1.m_u64value / sn2.m_u64value);
			else
				return new StackNumericValue(sn1.m_floatvalue / sn2.m_floatvalue);
		}

		/// <summary>
		/// Simulate a multiply operation.
		/// </summary>
		internal static StackNumericValue SimulateMult(StackNumericValue sn1, StackNumericValue sn2, IREvalStackPrimitiveType evst)
		{
			if(evst is IREvalStackTypeInt32)
				return new StackNumericValue(sn1.m_i32value * sn2.m_i32value);
			else if(evst is IREvalStackTypeInt64)
				return new StackNumericValue(sn1.m_i64value * sn2.m_i64value);
			else
				return new StackNumericValue(sn1.m_floatvalue * sn2.m_floatvalue);
		}

		/// <summary>
		/// Simulate a multiply operation (unsigned).
		/// </summary>
		internal static StackNumericValue SimulateMultUnsigned(StackNumericValue sn1, StackNumericValue sn2, IREvalStackPrimitiveType evst)
		{
			if(evst is IREvalStackTypeInt32)
				return new StackNumericValue(sn1.m_u32value * sn2.m_u32value);
			else if(evst is IREvalStackTypeInt64)
				return new StackNumericValue(sn1.m_u64value * sn2.m_u64value);
			else
				return new StackNumericValue(sn1.m_floatvalue * sn2.m_floatvalue);
		}

		/// <summary>
		/// Simulate a negate operation.
		/// </summary>
		internal static StackNumericValue SimulateNeg(StackNumericValue sn, IREvalStackPrimitiveType evst)
		{
			if(evst is IREvalStackTypeInt32)
				return new StackNumericValue(-sn.m_i32value);
			else if(evst is IREvalStackTypeInt64)
				return new StackNumericValue(-sn.m_i64value);
			else
				return new StackNumericValue(-sn.m_floatvalue);
		}

		/// <summary>
		/// Simulate a remainder operation.
		/// </summary>
		internal static StackNumericValue SimulateRem(StackNumericValue sn1, StackNumericValue sn2, IREvalStackPrimitiveType evst)
		{
			if(evst is IREvalStackTypeInt32)
				return new StackNumericValue(sn1.m_i32value % sn2.m_i32value);
			else if(evst is IREvalStackTypeInt64)
				return new StackNumericValue(sn1.m_i64value % sn2.m_i64value);
			else
				return new StackNumericValue(sn1.m_floatvalue % sn2.m_floatvalue);
		}

		/// <summary>
		/// Simulate a remainder operation (unsigned).
		/// </summary>
		internal static StackNumericValue SimulateRemUnsigned(StackNumericValue sn1, StackNumericValue sn2, IREvalStackPrimitiveType evst)
		{
			if(evst is IREvalStackTypeInt32)
				return new StackNumericValue(sn1.m_u32value % sn2.m_u32value);
			else if(evst is IREvalStackTypeInt64)
				return new StackNumericValue(sn1.m_u64value % sn2.m_u64value);
			else
				return new StackNumericValue(sn1.m_floatvalue % sn2.m_floatvalue);
		}

		/// <summary>
		/// Simulate a subtract operation.
		/// </summary>
		internal static StackNumericValue SimulateSub(StackNumericValue sn1, StackNumericValue sn2, IREvalStackPrimitiveType evst)
		{
			if(evst is IREvalStackTypeInt32)
				return new StackNumericValue(sn1.m_i32value - sn2.m_i32value);
			else if(evst is IREvalStackTypeInt64)
				return new StackNumericValue(sn1.m_i64value - sn2.m_i64value);
			else
				return new StackNumericValue(sn1.m_floatvalue - sn2.m_floatvalue);
		}

		/// <summary>
		/// Simulate a subtract operation (unsigned).
		/// </summary>
		internal static StackNumericValue SimulateSubUnsigned(StackNumericValue sn1, StackNumericValue sn2, IREvalStackPrimitiveType evst)
		{
			if(evst is IREvalStackTypeInt32)
				return new StackNumericValue(sn1.m_u32value - sn2.m_u32value);
			else if(evst is IREvalStackTypeInt64)
				return new StackNumericValue(sn1.m_u64value - sn2.m_u64value);
			else
				return new StackNumericValue(sn1.m_floatvalue - sn2.m_floatvalue);
		}

		//////////////
		//Primitive Bitwise Operations

		/// <summary>
		/// Simulate an and operation.
		/// </summary>
		internal static StackNumericValue SimulateAnd(StackNumericValue sn1, StackNumericValue sn2, IREvalStackPrimitiveType evst)
		{
			if(evst is IREvalStackTypeInt32)
				return new StackNumericValue(sn1.m_u32value & sn2.m_u32value);
			else
				return new StackNumericValue(sn1.m_u64value & sn2.m_u64value);
		}

		/// <summary>
		/// Simulate an or operation.
		/// </summary>
		internal static StackNumericValue SimulateOr(StackNumericValue sn1, StackNumericValue sn2, IREvalStackPrimitiveType evst)
		{
			if(evst is IREvalStackTypeInt32)
				return new StackNumericValue(sn1.m_u32value | sn2.m_u32value);
			else
				return new StackNumericValue(sn1.m_u64value | sn2.m_u64value);
		}

		/// <summary>
		/// Simulate a not operation.
		/// </summary>
		internal static StackNumericValue SimulateNot(StackNumericValue sn, IREvalStackPrimitiveType evst)
		{
			if(evst is IREvalStackTypeInt32)
				return new StackNumericValue(~sn.m_u32value);
			else
				return new StackNumericValue(~sn.m_u64value);
		}

		/// <summary>
		/// Simulate a shl operation.
		/// </summary>
		internal static StackNumericValue SimulateShl(StackNumericValue sn1, StackNumericValue sn2, IREvalStackPrimitiveType evst)
		{
			int sval = sn2.m_i32value;
			Debug.Assert(sval >= 0);

			if(evst is IREvalStackTypeInt32)
				return new StackNumericValue(sn1.m_u32value << sval);
			else
				return new StackNumericValue(sn1.m_u64value << sval);
		}

		/// <summary>
		/// Simulate a shr operation.
		/// </summary>
		internal static StackNumericValue SimulateShr(StackNumericValue sn1, StackNumericValue sn2, IREvalStackPrimitiveType evst)
		{
			int sval = sn2.m_i32value;
			Debug.Assert(sval >= 0);

			if(evst is IREvalStackTypeInt32)
				return new StackNumericValue(sn1.m_i32value >> sval);
			else
				return new StackNumericValue(sn1.m_i64value >> sval);
		}

		/// <summary>
		/// Simulate a shr operation (unsigned).
		/// </summary>
		internal static StackNumericValue SimulateShrUnsigned(StackNumericValue sn1, StackNumericValue sn2, IREvalStackPrimitiveType evst)
		{
			int sval = sn2.m_i32value;
			Debug.Assert(sval >= 0);

			if(evst is IREvalStackTypeInt32)
				return new StackNumericValue(sn1.m_u32value >> sval);
			else
				return new StackNumericValue(sn1.m_u64value >> sval);
		}

		/// <summary>
		/// Simulate an xor operation.
		/// </summary>
		internal static StackNumericValue SimulateXor(StackNumericValue sn1, StackNumericValue sn2, IREvalStackPrimitiveType evst)
		{
			if(evst is IREvalStackTypeInt32)
				return new StackNumericValue(sn1.m_u32value ^ sn2.m_u32value);
			else
				return new StackNumericValue(sn1.m_u64value ^ sn2.m_u64value);
		}
	}
}

